using System;
using System.IO;
using WCell.Constants;
using WCell.Constants.Spells;
using WCell.Core.Network;
using WCell.RealmServer.Entities;
using WCell.RealmServer.Network;

namespace WCell.RealmServer.Spells.Auras
{
	public static partial class AuraHandler
	{
		/// <summary>
		/// Cancels a positive aura (by right-clicking on the corresponding icon)
		/// </summary>
		[ClientPacketHandler(RealmServerOpCode.CMSG_CANCEL_AURA)]
		public static void HandleCancelCastSpell(IRealmClient client, RealmPacketIn packet)
		{
			var spellId = (SpellId)packet.ReadUInt32();

			var spell = SpellHandler.Get(spellId);
			if (spell != null)
			{
				var chr = client.ActiveCharacter;
				var aura = chr.Auras[spell, true];

				if (aura != null && aura.CanBeCancelled)
				{
					aura.TryRemove(true);
				}
			}
		}

		public static void SendAuraUpdate(Unit owner, Aura aura)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AURA_UPDATE))
			{
				owner.EntityId.WritePacked(packet);

				WriteAura(aura, packet);

				owner.SendPacketToArea(packet);
			}
		}

		public static void SendAllAuras(IPacketReceiver rcv, Unit owner)
		{
			using (var packet = CreateAllAuraPacket(owner))
			{
				rcv.Send(packet);
			}
		}

		public static void SendAllAuras(Unit owner)
		{
			using (var packet = CreateAllAuraPacket(owner))
			{
				owner.SendPacketToArea(packet);
			}
		}

		public static RealmPacketOut CreateAllAuraPacket(Unit owner)
		{
			var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AURA_UPDATE_ALL);
			owner.EntityId.WritePacked(packet);
			foreach (var aura in owner.Auras.ActiveAuras)
			{
				if (aura.IsVisible)
				{
					WriteAura(aura, packet);
				}
			}
			return packet;
		}

		private static void WriteAura(Aura aura, BinaryWriter packet)
		{
			packet.Write(aura.Index);

			packet.Write(aura.Spell.Id);

			packet.Write((byte)aura.Flags);
			packet.Write(aura.Level);
			packet.Write((byte)aura.RemainingCharges);

			// If the target was not the caster
			if (!aura.Flags.Has(AuraFlags.TargetIsCaster))
			{
				aura.Caster.EntityId.WritePacked(packet);
			}

			if (aura.Flags.Has(AuraFlags.HasDuration))
			{
				packet.Write(aura.Duration);
				packet.Write(aura.TimeLeft);
			}
		}

		public static void SendRemoveAura(Unit owner, Aura aura)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AURA_UPDATE))
			{
				owner.EntityId.WritePacked(packet);
				packet.Write(aura.Index);

				// a spellid of 0 tells the client to remove the aura
				packet.Write(0);

				owner.SendPacketToArea(packet);
			}
		}
	}
}
